﻿using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Reflection;
using System.Data;
using System.ComponentModel;
using System.Collections;
using System.Linq.Expressions;
using Skynet.CommonLibrary.WCF;

namespace Skynet.CommonLibrary.Extension
{
    /// <summary>
    /// 动态接口帮助类
    /// </summary>
    public class DynamicInterfaceHelper
    {
        //缓存的最小生命周期（分钟）
        public const int CacheLift = 10;

        /// <summary>
        /// 具体实现类 关系映射（类名称）
        /// </summary>
        public static Func<string, string> RelationShipAction { get; set; }

        /// <summary>
        /// 通过 接口类型 转换成 具体的实现
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T ConvertAnonymousTypeToInterface<T>(Type baseclassType, Action<ILGenerator, TypeBuilder, MethodInfo, bool> action) where T : class
        {
            Type interfaceType = typeof(T);
            T tinterface = HttpRuntimeCache.GetCache<T>(interfaceType.Name);
            if (tinterface != null)
                return tinterface;

            // 必须是接口
            if (!typeof(T).IsInterface)
                throw new InvalidOperationException("T 必须是接口类型");

            if (!typeof(T).IsPublic)
                throw new InvalidOperationException("接口必须是公共的");


            //创建DLL
            AssemblyName assemblyName = new AssemblyName("DynamicInterface") {Version = new Version("1.0.0.0")};

            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly
                (assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule
                ("DynamicInterface", "DynamicInterface.dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType
                ("DynamicInterface." + interfaceType.Name + new Random().Next(), TypeAttributes.Public, baseclassType);

            //生成一个类 必须继承自接口T
            typeBuilder.AddInterfaceImplementation(interfaceType);

            //生成默认构造函数
            //typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);

            BuildPropertie(interfaceType, typeBuilder);

            string className = RelationShipAction != null ? RelationShipAction(interfaceType.Name) : DefaultRelationShip(interfaceType.Name);
            if (string.IsNullOrEmpty(className))
            {
                className = interfaceType.Name;
            }

            BuildMethod(interfaceType, typeBuilder, className,action);

            Type anonymousInterfaceType = typeBuilder.CreateType();
            //assemblyBuilder.Save("DynamicInterface.dll");

            T instance = Activator.CreateInstance(anonymousInterfaceType) as T;

            HttpRuntimeCache.SetCache(interfaceType.Name, instance, CacheLift);
            return instance;
        }

        /// <summary>
        /// wcf 通用接口类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T ConvertAnonymousTypeToInterface<T>() where T : class
        {
            return ConvertAnonymousTypeToInterface<T>(typeof(DataCenterBase), (ilGen, typeBuilder,mi, isExprecess) =>
            {
                 MethodInfo baseMethodInfo = null;
                if (isExprecess)
                {
                    if (typeBuilder.BaseType != null)
                        baseMethodInfo = typeBuilder.BaseType.GetMethod("GetServiceExpress", BindingFlags.Instance | BindingFlags.NonPublic);
                    if (baseMethodInfo != null)
                        ilGen.Emit(OpCodes.Call, baseMethodInfo.MakeGenericMethod(mi.ReturnType, mi.ReturnType.GetGenericArguments()[0]));
                }
                else
                {
                    if (mi.ReturnType == typeof(void))
                    {

                    }
                    else
                    {
                        if (typeBuilder.BaseType != null)
                            baseMethodInfo = typeBuilder.BaseType.GetMethod("GetService", BindingFlags.Instance | BindingFlags.NonPublic,
                                                                            null,
                                                                            new Type[] { typeof(string), typeof(string), typeof(string), typeof(object[]) },
                                                                            null);
                        if (baseMethodInfo != null)
                            ilGen.Emit(OpCodes.Call, baseMethodInfo.MakeGenericMethod(mi.ReturnType));
                    }
                }
            });
        }

        /// <summary>
        /// 通过DataSet 转换成实体集合
        /// </summary>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static IList ConvertAnonymousDataSetToEntity(DataSet ds)
        {
            //创建DLL
            AssemblyName assemblyName = new AssemblyName("DynamicInterface") {Version = new Version("1.0.0.0")};

            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly
                (assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule
                ("DynamicInterface", "DynamicInterface.dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType
                ("DynamicInterface." + new Random().Next(), TypeAttributes.Public, null);

            if (!ds.Tables[0].Columns.Contains("Dynamic_ID"))
            {
                //为列创建 唯一序号
                ds.Tables[0].Columns.Add("Dynamic_ID", typeof(Decimal));
            }

            //创建属性
            BuildPropertie(ds.Tables[0].Columns, typeBuilder);
            Type anonymousInterfaceType = typeBuilder.CreateType();

            //反射创建泛型集合
            Type generic = typeof(List<>);
            Type[] typeArgs1 = { anonymousInterfaceType };
            generic = generic.MakeGenericType(typeArgs1);
            IList list = generic.CreateInstance<IList>();

            //生成集合
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                DataRow row = ds.Tables[0].Rows[i];
                object obj = Activator.CreateInstance(anonymousInterfaceType);
                foreach (PropertyInfo info in obj.GetType().GetProperties())
                {
                    if (info.Name == "Dynamic_ID")
                    {
                        obj.SetValue(info.Name, (Decimal)i);
                    }
                    else
                    {
                        obj.SetValue(info.Name, row[info.Name]);
                    }
                }
                list.Add(obj);
            }

            return list;
        }

        //构建属性
        private static void BuildPropertie(Type interfaceType, TypeBuilder typeBuilder)
        {
            //获得接口中的属性
            PropertyDescriptorCollection interfaceProperties =
                TypeDescriptor.GetProperties(interfaceType);

            foreach (PropertyDescriptor interfaceProperty in interfaceProperties)
            {
                BuildProperty(interfaceProperty.Name, interfaceProperty.PropertyType,typeBuilder);
            }
        }
        private static void BuildPropertie(DataColumnCollection columns, TypeBuilder typeBuilder)
        {
            foreach (DataColumn column in columns)
            {
                if (column.DataType == typeof(string) || column.DataType == typeof(Byte[]))
                { 
                    BuildProperty(column.ColumnName, column.DataType, typeBuilder); 
                }
                else
                {
                    BuildProperty(column.ColumnName, typeof(Nullable<>).MakeGenericType(column.DataType), typeBuilder);
                }
            }
        }
        private static void BuildProperty(string name, Type type, TypeBuilder typeBuilder) 
        {
           
            //生成私有变量
            FieldBuilder propertyFieldBuilder = typeBuilder.DefineField
                ("_" + name, type, FieldAttributes.Private);

            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(
              name, System.Reflection.PropertyAttributes.None,
              type, Type.EmptyTypes);

            const MethodAttributes getSetMethodAttributes = MethodAttributes.Public | MethodAttributes.Virtual;

            MethodBuilder propertyGetMethod = typeBuilder.DefineMethod(
                "get_" + name, getSetMethodAttributes,
                type, Type.EmptyTypes);

            ILGenerator getMethodGenerator = propertyGetMethod.GetILGenerator();
            getMethodGenerator.Emit(OpCodes.Ldarg_0);
            getMethodGenerator.Emit(OpCodes.Ldfld, propertyFieldBuilder);
            getMethodGenerator.Emit(OpCodes.Ret);

            MethodBuilder propertySetMethod = typeBuilder.DefineMethod(
                "set_" + name, getSetMethodAttributes,
                null, new Type[] { type });

            ILGenerator setMethodGenerator = propertySetMethod.GetILGenerator();
            setMethodGenerator.Emit(OpCodes.Ldarg_0);
            setMethodGenerator.Emit(OpCodes.Ldarg_1);
            setMethodGenerator.Emit(OpCodes.Stfld, propertyFieldBuilder);
            setMethodGenerator.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(propertyGetMethod);
            propertyBuilder.SetSetMethod(propertySetMethod);
        }

        //构建方法
        private static void BuildMethod(Type interfaceType, TypeBuilder typeBuilder, string className, Action<ILGenerator, TypeBuilder, MethodInfo, bool> action)
        {
            foreach (MethodInfo mi in interfaceType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                //获取参数类型
                bool isExprecess = false;
                bool isReference = false;

                //值类型 参数个数
                //int valueTypeCount = 0;
                ParameterInfo[] paramInfos = mi.GetParameters();
                Type[] argTypes = new Type[paramInfos.Length];
                int i = 0;
                foreach (ParameterInfo pi in paramInfos)
                {
                    argTypes[i++] = pi.ParameterType;

                    if (pi.ParameterType.IsValueType)
                    {
                        //valueTypeCount++;
                        continue;
                    }
                    if (pi.ParameterType == typeof(string))
                    {
                        //valueTypeCount++;
                    }
                    else if (pi.ParameterType.BaseType == typeof(LambdaExpression))
                    {
                        isExprecess = true;
                    }
                    isReference = true;
                }

                //构造方法
                MethodBuilder method = typeBuilder.DefineMethod(mi.Name,
                    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                    CallingConventions.Standard,
                    mi.ReturnType,
                    argTypes);

                //方法内容
                ILGenerator ilGen = method.GetILGenerator();
                //加载参数

                ilGen.Emit(OpCodes.Nop);
                ilGen.Emit(OpCodes.Ldarg_0);
                //参数1  类名称
                ilGen.Emit(OpCodes.Ldstr, className);
                //参数2 方法名称
                ilGen.Emit(OpCodes.Ldstr, mi.Name);
                //参数3 用户名
                ilGen.Emit(OpCodes.Ldstr, "");

                if (paramInfos.Length == 0)
                {
                    //如果参数是空
                    ilGen.Emit(OpCodes.Ldnull);
                }
                else
                {
                    //参数不为空 则创建一个数组 已用于装载参数
                    EmitLdc(ilGen, paramInfos.Length);
                    ilGen.Emit(OpCodes.Newarr, typeof(Object));
                }
                if (paramInfos.Length > 0)
                {
                    ilGen.Emit(OpCodes.Stloc_1);
                    ilGen.Emit(OpCodes.Ldloc_1);
                }

                //int valueCount = 0;
                for (int j = 0; j < argTypes.Length; j++)
                {
                    //if (argTypes[j].IsValueType || argTypes[j] == typeof(string))
                    //{
                    //如果方法参数 不包括引用类型 则要声明参数的类型
                    if (!isReference)
                    {
                        ilGen.DeclareLocal(argTypes[j]);
                    }
                    EmitLdc(ilGen, j);// valueCount);
                    //valueCount++;
                    EmitLdarg(ilGen, j + 1);
                    //将值类型装箱 放入到数组中
                    if (argTypes[j].IsValueType && argTypes[j] != typeof(string))
                    {
                        ilGen.Emit(OpCodes.Box, argTypes[j]);
                    }
                    ilGen.Emit(OpCodes.Stelem_Ref);
                    ilGen.Emit(OpCodes.Ldloc_1);
                    //}
                    //else
                    //{
                    //    EmitLdarg(ilGen, j + 1);
                    //}
                }

                //调用基类的方法
                if (action != null)
                {
                    action(ilGen, typeBuilder, mi,isExprecess);
                }
                //MethodInfo baseMethodInfo = null;
                //if (IsExprecess)
                //{
                //    baseMethodInfo = typeBuilder.BaseType.GetMethod("GetServiceExpress", BindingFlags.Instance | BindingFlags.NonPublic);
                //    ilGen.Emit(OpCodes.Call, baseMethodInfo.MakeGenericMethod(mi.ReturnType, mi.ReturnType.GetGenericArguments()[0]));
                //}
                //else
                //{
                //    baseMethodInfo = typeBuilder.BaseType.GetMethod("GetService", BindingFlags.Instance | BindingFlags.NonPublic,
                //        null,
                //        new Type[] { typeof(string), typeof(string), typeof(string), typeof(object[]) },
                //        null);
                //    ilGen.Emit(OpCodes.Call, baseMethodInfo.MakeGenericMethod(mi.ReturnType));
                //}

                //声明返回值类型
                if (isReference)
                {
                    ilGen.DeclareLocal(mi.ReturnType);
                    if (paramInfos.Length != 0)
                    {
                        ilGen.DeclareLocal(typeof(object[]));
                    }
                }
                else if (paramInfos.Length == 0)
                {
                    ilGen.DeclareLocal(mi.ReturnType);
                }
                if (mi.ReturnType != typeof(void))
                {
                    //if (mi.ReturnType.IsValueType || mi.ReturnType.IsGenericType || mi.ReturnType.IsGenericParameter)
                    //{
                    //    //是值类型,泛型参,泛型拖进来脱衣服
                    //    ilGen.Emit(OpCodes.Unbox_Any, mi.ReturnType);
                    //}
                    //else
                    //{
                    //    ilGen.Emit(OpCodes.Castclass, mi.ReturnType);
                    //}
                    ilGen.Emit(OpCodes.Stloc_0);
                    Label lab = ilGen.DefineLabel();
                    ilGen.Emit(OpCodes.Br_S, lab);
                    ilGen.MarkLabel(lab);
                    ilGen.Emit(OpCodes.Ldloc_0);
                    //ilGen.Emit(OpCodes.Ldloc_0);
                }
                else
                {
                    ilGen.Emit(OpCodes.Pop);
                }
                ilGen.Emit(OpCodes.Ret);
            }
        }
        //默认关系映射
        private static string DefaultRelationShip(string typeName)
        {
            return typeName.Substring(1);
        }

        private static void EmitLdc(ILGenerator gen, int index)
        {
            switch (index)
            {
                case 0:
                    gen.Emit(OpCodes.Ldc_I4_0);
                    break;
                case 1:
                    gen.Emit(OpCodes.Ldc_I4_1);
                    break;
                case 2:
                    gen.Emit(OpCodes.Ldc_I4_2);
                    break;
                case 3:
                    gen.Emit(OpCodes.Ldc_I4_3);
                    break;
                case 4:
                    gen.Emit(OpCodes.Ldc_I4_4);
                    break;
                case 5:
                    gen.Emit(OpCodes.Ldc_I4_5);
                    break;
                case 6:
                    gen.Emit(OpCodes.Ldc_I4_6);
                    break;
                case 7:
                    gen.Emit(OpCodes.Ldc_I4_7);
                    break;
                case 8:
                    gen.Emit(OpCodes.Ldc_I4_8);
                    break;
                default:
                    gen.Emit(index < 128 ? OpCodes.Ldc_I4_S : OpCodes.Ldc_I4, index);
                    break;
            }
        }
        //private static void EmitStloc(ILGenerator gen, int index)
        //{
        //    switch (index)
        //    {
        //        case 0:
        //            gen.Emit(OpCodes.Stloc_0);
        //            break;
        //        case 1:
        //            gen.Emit(OpCodes.Stloc_1);
        //            break;
        //        case 2:
        //            gen.Emit(OpCodes.Stloc_2);
        //            break;
        //        case 3:
        //            gen.Emit(OpCodes.Stloc_3);
        //            break;
        //        default:
        //            gen.Emit(index < 128 ? OpCodes.Stloc_S : OpCodes.Stloc, index);
        //            break;
        //    }
        //}
        //private static void EmitLdloc(ILGenerator gen, int index)
        //{
        //    switch (index)
        //    {
        //        case 0:
        //            gen.Emit(OpCodes.Ldloc_0);
        //            break;
        //        case 1:
        //            gen.Emit(OpCodes.Ldloc_1);
        //            break;
        //        case 2:
        //            gen.Emit(OpCodes.Ldloc_2);
        //            break;
        //        case 3:
        //            gen.Emit(OpCodes.Ldloc_3);
        //            break;
        //        default:
        //            gen.Emit(index < 128 ? OpCodes.Ldloc_S : OpCodes.Ldloc, index);
        //            break;
        //    }
        //}
        private static void EmitLdarg(ILGenerator gen, int index)
        {
            switch (index)
            {
                case 0:
                    gen.Emit(OpCodes.Ldarg_0);
                    break;
                case 1:
                    gen.Emit(OpCodes.Ldarg_1);
                    break;
                case 2:
                    gen.Emit(OpCodes.Ldarg_2);
                    break;
                case 3:
                    gen.Emit(OpCodes.Ldarg_3);
                    break;
                default:
                    gen.Emit(OpCodes.Ldarg_S, index);
                    break;
            }
        }
    }
}
